package BusinessLogic;

import Domain.User;
import Domain.SearchUserMethods;
import Domain.MySqlAccessors.MySqlUserProxy;
import Domain.Exceptions.UserNotExistException;
import Domain.Exceptions.PassowrdIncorrectException;
import Domain.Exceptions.UserNotLoggedInException;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Collection;
import java.util.LinkedList;

import org.apache.log4j.Logger;
import BusinessLogic.Exceptions.UserAlreadyExistException;
import BusinessLogic.Exceptions.DataAlreadyExistException;
import Persistance.MySqlUtilityManagment;

public class UserHandler implements IHandlers<User>, Serializable {
    static Logger logger = Logger.getLogger("MovieSystem.BussinessLogic.UserHandler");

    private MySqlUserProxy m_users;
    private HashMap<Object, String> m_terminals;
    private HashMap<String, User> m_onlineUsers;

    /* Constructor */
    public UserHandler(MySqlUtilityManagment sql) {
        m_users = new MySqlUserProxy(sql);
        
        this.m_terminals = new HashMap<Object, String>();
        this.m_onlineUsers = new HashMap<String, User>();
    }

    /* Methods */
    public User get(String username){
        return m_users.getRecord(username);
    }

    public void add(User user){
        if(user != null) {
            logger.info("Add user "+ user.getUsername() +" to dataBase");
            try {
                m_users.addRecord(user);
            }
            catch (DataAlreadyExistException e) {
                e.printStackTrace();
            }
        }
        else {
            logger.error("Adding a null user. ignoring comnand.");
        }
    }

    public void delete(User user){
        if(user != null){
            logger.info("Delete user "+ user.getUsername() +" from dataBase");
            try{
                logout(user.getUsername());
            }
            catch (Exception e) {
                logger.info("User "+ user.getUsername() +" couldn't be logged out on delete");
            }
            finally{
                m_users.deleteRecord(user.getUsername());
            }
        }
        else{
            logger.error("Deleting a null user. ignoring comnand.");
        }
    }

    public void delete(String username){
        delete(get(username));
    }

    public void loginAuthenticate(Object terminal, String username, String encPass) throws UserNotExistException, PassowrdIncorrectException {
        logger.info("Preforming login verify check");

        User u;
        if (m_onlineUsers.containsKey(username))
            u = m_onlineUsers.get(username);
        else
            u = get(username);

        if(u != null){      /* user exsists */
            if (encPass.equals(u.getEncryptedPassword())){ /* password correct */
                if (m_terminals.containsKey(terminal)){   /* Someone is connected in the terminal */
                    User other = m_onlineUsers.get(m_terminals.get(terminal));
                    if (other.getUsername().equals(username)){
                        logger.info("user "+username+" is already connected in terminal "+terminal);
                        return;
                    }
                    logger.info("cleaning terminal status for "+u.getTerminal());
                    other.setState(null,User.SESSION_DROPPED); /* set user state */
                    m_terminals.remove(u.getTerminal());
                    m_onlineUsers.remove(u.getUsername());
                }
                if (u.getState() == User.ONLINE && u.getTerminal() != terminal){
                    logger.info("user "+u.getUsername()+" removed from terminal "+u.getTerminal());
                    m_terminals.remove(u.getTerminal());                    
                }
                logger.info("user "+username+" logged in from terminal "+terminal);
                u.setState(terminal,User.ONLINE);  /* set user online */
                m_terminals.put(terminal,username);
                m_onlineUsers.put(username,u);
            }
            else
                throw new PassowrdIncorrectException(username);
        }

        else throw new UserNotExistException(username);
    }

    public void logout(String username) throws UserNotExistException, UserNotLoggedInException {
        User u = m_onlineUsers.get(username);
        if(u != null){      /* user exsists */
            if (u.getState() == User.ONLINE){
                logger.info("user "+username+" logged out from terminal "+u.getTerminal());
                m_terminals.remove(u.getTerminal());
                m_onlineUsers.remove(u.getUsername());
                u.setState(null,User.OFFLINE); /* set user state */
            }
            else throw new UserNotLoggedInException(username);
        }
        else throw new UserNotExistException(username);
    }

    public synchronized void addNewUser(String username, String firstname, String lastname, String encPass, boolean VIP, String email, String acl) throws UserAlreadyExistException {
        if (get(username) != null)
            throw new UserAlreadyExistException(username);
        User u = new User(username, firstname, lastname, encPass, VIP, email, acl);
        add(u);
    }

    public Collection<String> getOnlineUsers(){
        return new LinkedList<String>(m_onlineUsers.keySet());
    }

    public User getCurrentUser(Object terminal) {
        return m_onlineUsers.get(m_terminals.get(terminal));
    }

    public Collection<User> getUsers(){
        return m_users.searchRecords("all");
    }

    public Collection<String> getUserNames(){
        return m_users.getUserNames();
    }

    public String[] searchUser(String keyword, SearchUserMethods sm, int start, int amount, String startWith) {
        logger.info("Searching users, filtered by "+sm+"='"+keyword+"'");
        return m_users.searchUsers(keyword,sm,start,amount,startWith);
    }
}
